package structs

import (
	"bytes"
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"io"
	"log"
	"mime/multipart"
	"net/http"
	"os"
	"time"
)

func PageCount(size int, partSize int) int {
	var partCount = size / partSize
	if 0 != size%partSize {
		partCount++
	}

	return partCount
}

func SHA256File(filename string, n ...int64) ([]byte, error) {
	ha := sha256.New()

	fp, err := os.Open(filename)
	if err != nil {
		return nil, err
	} else {
		defer fp.Close()
	}

	var r io.Reader = fp
	if len(n) > 0 && n[0] > 0 {
		r = io.LimitReader(fp, n[0])
	}

	if _, err = io.Copy(ha, r); err != nil {
		return nil, err
	}

	return ha.Sum(nil), nil
}

func SHA256(date []byte) string {
	h := sha256.New()
	h.Write(date)
	return hex.EncodeToString(h.Sum(nil))
}

// IsExists 判断所给路径文件/文件夹是否存在
func IsExists(path string) bool {
	_, err := os.Lstat(path) //os.Stat获取文件信息
	if err != nil {
		return os.IsExist(err)
	}

	return true
}

// NewMultipartFormData multipart/form-data
func NewMultipartFormData(cli *http.Client, uri string, params map[string]string, fieldName, filename string, data []byte, headers map[string]string) ([]byte, error) {
	var (
		err  error
		body = &bytes.Buffer{}

		writer *multipart.Writer
		part   io.Writer

		request *http.Request
	)

	// multipart
	writer = multipart.NewWriter(body)
	for k, v := range params {
		_ = writer.WriteField(k, v)
	}

	if part, err = writer.CreateFormFile(fieldName, filename); err != nil {
		return nil, err
	}

	if _, err = part.Write(data); err != nil {
		return nil, err
	}

	_ = writer.Close()

	if request, err = http.NewRequest(http.MethodPut, uri, body); err != nil {
		return nil, err
	} else {
		request.Header.Set("Content-Type", writer.FormDataContentType())

		for key, value := range headers {
			request.Header.Set(key, value)
		}
	}

	//start := time.Now()
	resp, err := cli.Do(request)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	res, err := io.ReadAll(resp.Body)

	//log.Printf("-- http [%v] [%v] [%v]", uri, time.Since(start), fieldName)

	return res, err
}

// HttpRequest http请求
func HttpRequest(cli *http.Client, method string, url string, p io.Reader, contextType string, headers map[string]string) ([]byte, time.Duration, error) {
	req, err := http.NewRequest(method, url, p)
	if err != nil {
		return nil, 0, err
	}

	if len(contextType) > 0 {
		req.Header.Add("Content-Type", contextType)
	}

	for key, value := range headers {
		req.Header.Set(key, value)
	}

	start := time.Now()
	resp, err := cli.Do(req)
	if err != nil {
		log.Printf("-- http [%v] [%v] [%v] error: %v", method, url, time.Since(start), err)
		return nil, time.Since(start), err
	}
	defer resp.Body.Close()

	data, err := io.ReadAll(resp.Body)
	if err != nil {
		log.Printf("-- http [%v] [%v] [%v] error: %v", method, url, time.Since(start), err)
		return nil, time.Since(start), err
	}

	// log.Printf("-- http [%v] [%v] [%v]", method, url, time.Since(start))

	return data, time.Since(start), nil
}

// FormatJson 格式化json字符串
func FormatJson(data []byte) []byte {
	var obj interface{}
	if err := json.Unmarshal(data, &obj); err != nil {
		return data
	}

	if data2, err := json.MarshalIndent(obj, "", "  "); err != nil {
		return data
	} else {
		return data2
	}
}

// FormatJsonString 格式化json字符串
func FormatJsonString(data []byte) string {
	return string(FormatJson(data))
}
